package com.vaadin.incubator.bugrap.tests.model;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import com.vaadin.incubator.bugrap.PasswordGenerator;
import com.vaadin.incubator.bugrap.model.facade.FacadeFactory;
import com.vaadin.incubator.bugrap.model.facade.FacadeUtil;
import com.vaadin.incubator.bugrap.model.projects.Project;
import com.vaadin.incubator.bugrap.model.projects.ProjectVersion;
import com.vaadin.incubator.bugrap.model.reports.Report;
import com.vaadin.incubator.bugrap.model.reports.ReportStatus;
import com.vaadin.incubator.bugrap.model.users.Reporter;

public class FacadeUtilTest extends TestBase {

	@Test
	public void testStore() {
		Reporter r = new Reporter();
		r = FacadeUtil.store(r);

		assertNotSame(-1, r.getId());

		Reporter x = FacadeFactory.getFacade().find(Reporter.class, r.getId());
		assertEquals(r, x);
	}

	@Test
	public void testGetUnassignedReports() {

		// Add a test project
		Project p = new Project();
		p = FacadeUtil.store(p);

		// Add some unassigned reports
		Report r = new Report();
		r.setTimestamp(new Date());
		r.setProject(p);
		r.setSummary("Report1");
		FacadeUtil.store(r);

		r = new Report();
		r.setTimestamp(new Date());
		r.setProject(p);
		r.setSummary("Report2");
		FacadeUtil.store(r);

		List<Report> reports = FacadeUtil.getUnassignedReports(p);
		assertEquals(2, reports.size());
		assertEquals("Report1", reports.get(0).getSummary());
		assertEquals("Report2", reports.get(1).getSummary());

	}

	@Test
	public void testGetReportsForVersion() {

		// Add a test project
		Project p = new Project();
		p = FacadeUtil.store(p);

		// Add a test version
		ProjectVersion v = new ProjectVersion();
		v.setProject(p);
		v = FacadeUtil.store(v);

		// Add some versioned reports
		Report r = new Report();
		r.setTimestamp(new Date());
		r.setProject(p);
		r.setVersion(v);
		r.setSummary("Report1");
		FacadeUtil.store(r);

		r = new Report();
		r.setTimestamp(new Date());
		r.setProject(p);
		r.setVersion(v);
		r.setSummary("Report2");
		FacadeUtil.store(r);

		List<Report> versioned = FacadeUtil.getReportsForVersion(v);
		assertEquals(2, versioned.size());
		assertEquals("Report1", versioned.get(0).getSummary());
		assertEquals("Report2", versioned.get(1).getSummary());
	}

	@Test
	public void testGetUser() throws NoSuchAlgorithmException,
			UnsupportedEncodingException {

		// Add a reporter
		Reporter r = new Reporter();
		r.setName("name");
		r.setPassword(PasswordGenerator.encrypt("password"));
		r = FacadeUtil.store(r);

		Reporter x = FacadeUtil.getUser("name", "password");
		assertEquals(r, x);
	}

	@Test
	public void testGetProjects() {
		// Add some projects
		Project p = new Project();
		p.setName("Project1");
		FacadeUtil.store(p);
		p = new Project();
		p.setName("Project2");
		FacadeUtil.store(p);
		p = new Project();
		p.setName("Project3");
		FacadeUtil.store(p);

		List<Project> projects = FacadeUtil.getProjects();
		assertEquals(3, projects.size());
		assertEquals("Project1", projects.get(0).getName());
		assertEquals("Project2", projects.get(1).getName());
		assertEquals("Project3", projects.get(2).getName());
	}

	@Test
	public void testGetActiveProjects() {

		// Active ( One open project)
		Project p = new Project();
		p.setName("Project1");
		p = FacadeUtil.store(p);

		ProjectVersion v = new ProjectVersion();
		v.setProject(p);
		v.setClosed(false);
		FacadeUtil.store(v);

		// Active ( One open / one closed project)
		p = new Project();
		p.setName("Project2");
		p = FacadeUtil.store(p);

		v = new ProjectVersion();
		v.setProject(p);
		v.setClosed(false);
		FacadeUtil.store(v);

		v = new ProjectVersion();
		v.setProject(p);
		v.setClosed(true);
		FacadeUtil.store(v);

		// Inactive ( No versions)
		p = new Project();
		p.setName("Project3");
		FacadeUtil.store(p);

		// Inactive ( One closed version)
		p = new Project();
		p.setName("Project4");
		p = FacadeUtil.store(p);

		v = new ProjectVersion();
		v.setProject(p);
		v.setClosed(true);
		FacadeUtil.store(v);

		List<Project> active = FacadeUtil.getActiveProjects();
		assertEquals(2, active.size());
		assertEquals("Project1", active.get(0).getName());
		assertEquals("Project2", active.get(1).getName());
	}

	@Test
	public void testGetProject() {
		// Add a project to get
		Project p = new Project();
		p = FacadeUtil.store(p);

		Project x = FacadeUtil.getProject(p.getId());
		assertEquals(p, x);
	}

	@Test
	public void testGetVersion() {
		ProjectVersion v = new ProjectVersion();
		v = FacadeUtil.store(v);

		ProjectVersion x = FacadeUtil.getVersion(v.getId());
		assertEquals(v, x);
	}

	@Test
	public void testGetReport() {
		Report r = new Report();
		r = FacadeUtil.store(r);

		Report x = FacadeUtil.getReport(r.getId());
		assertEquals(r, x);
	}

	@Test
	public void testGetReporter() {
		Reporter r = new Reporter();
		r = FacadeUtil.store(r);

		Reporter x = FacadeUtil.getReporter(r.getId());
		assertEquals(r, x);
	}

	@Test
	public void testGetReporterByNameOrEmail() {
		Reporter r = new Reporter();
		r.setName("name");
		r.setEmail("email");
		r = FacadeUtil.store(r);

		// By name
		Reporter x = FacadeUtil.getReporterByNameOrEmail("name", null);
		assertEquals(r, x);

		// By email
		Reporter y = FacadeUtil.getReporterByNameOrEmail(null, "email");
		assertEquals(r, y);

		// By both
		Reporter z = FacadeUtil.getReporterByNameOrEmail("name", "email");
		assertEquals(r, z);
	}

	@Test
	public void testGetReporters() {
		Reporter r = new Reporter();
		r.setName("Reporter1");
		FacadeUtil.store(r);
		r = new Reporter();
		r.setName("Reporter2");
		FacadeUtil.store(r);
		r = new Reporter();
		r.setName("Reporter3");
		FacadeUtil.store(r);

		List<Reporter> reporters = FacadeUtil.getReporters();
		assertEquals(3, reporters.size());
		assertEquals("Reporter1", reporters.get(0).getName());
		assertEquals("Reporter2", reporters.get(1).getName());
		assertEquals("Reporter3", reporters.get(2).getName());
	}

	@Test
	public void testGetVersions() {
		ProjectVersion pv = new ProjectVersion();
		pv.setVersion("Version1");
		FacadeUtil.store(pv);
		pv = new ProjectVersion();
		pv.setVersion("Version2");
		FacadeUtil.store(pv);
		pv = new ProjectVersion();
		pv.setVersion("Version3");
		FacadeUtil.store(pv);

		List<ProjectVersion> versions = FacadeUtil.getVersions();
		assertEquals(3, versions.size());
		assertEquals("Version1", versions.get(0).getVersion());
		assertEquals("Version2", versions.get(1).getVersion());
		assertEquals("Version3", versions.get(2).getVersion());
	}

	@Test
	public void testGetLatestReportsInt() {
		Calendar cal = Calendar.getInstance();

		Report r = new Report();
		r.setSummary("Report1");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		cal.add(Calendar.DAY_OF_MONTH, 1);

		r = new Report();
		r.setSummary("Report2");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		cal.add(Calendar.DAY_OF_MONTH, 1);

		r = new Report();
		r.setSummary("Report3");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		cal.add(Calendar.DAY_OF_MONTH, 1);

		r = new Report();
		r.setSummary("Report4");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		List<Report> reports = FacadeUtil.getLatestReports(2);
		assertEquals(2, reports.size());
		assertEquals("Report4", reports.get(0).getSummary());
		assertEquals("Report3", reports.get(1).getSummary());
	}

	@Test
	public void testGetLatestReportsProjectProjectVersionInt() {
		Project p = new Project();
		p = FacadeUtil.store(p);

		ProjectVersion pv = new ProjectVersion();
		pv = FacadeUtil.store(pv);

		Calendar cal = Calendar.getInstance();

		// Report with only project
		Report r = new Report();
		r.setSummary("Report1");
		r.setProject(p);
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		cal.add(Calendar.DAY_OF_MONTH, 1);

		// Report with only version
		r = new Report();
		r.setVersion(pv);
		r.setSummary("Report2");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		cal.add(Calendar.DAY_OF_MONTH, 1);

		// Report with project and version
		r = new Report();
		r.setProject(p);
		r.setVersion(pv);
		r.setSummary("Report3");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		cal.add(Calendar.DAY_OF_MONTH, 1);

		// Report with project and version
		r = new Report();
		r.setProject(p);
		r.setVersion(pv);
		r.setSummary("Report4");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		cal.add(Calendar.DAY_OF_MONTH, 1);

		// Report with project and version
		r = new Report();
		r.setProject(p);
		r.setVersion(pv);
		r.setSummary("Report5");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		cal.add(Calendar.DAY_OF_MONTH, 1);

		// Report with no project or version
		r = new Report();
		r.setSummary("Report6");
		r.setTimestamp(cal.getTime());
		r = FacadeUtil.store(r);

		List<Report> reports = FacadeUtil.getLatestReports(p, pv, 2);
		assertEquals(2, reports.size());
		assertEquals("Report5", reports.get(0).getSummary());
		assertEquals("Report4", reports.get(1).getSummary());

		reports = FacadeUtil.getLatestReports(p, null, 2);
		assertEquals(1, reports.size());
		assertEquals("Report1", reports.get(0).getSummary());

		reports = FacadeUtil.getLatestReports(null, pv, 2);
		assertEquals(1, reports.size());
		assertEquals("Report2", reports.get(0).getSummary());

		reports = FacadeUtil.getLatestReports(null, null, 2);
		assertEquals(1, reports.size());
		assertEquals("Report6", reports.get(0).getSummary());
	}

	@Test
	public void testCountReportsProjectVersionReportStatus() {
		ProjectVersion pv = new ProjectVersion();
		pv = FacadeUtil.store(pv);

		Report r = new Report();
		r.setVersion(pv);
		r.setStatus(ReportStatus.OPEN);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setVersion(pv);
		r.setStatus(ReportStatus.OPEN);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setVersion(pv);
		r.setStatus(ReportStatus.CLOSED);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setVersion(pv);
		r.setStatus(ReportStatus.CLOSED);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setVersion(pv);
		r.setStatus(ReportStatus.CLOSED);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setStatus(ReportStatus.CLOSED);
		r = FacadeUtil.store(r);

		long open = FacadeUtil.countReports(pv, ReportStatus.OPEN);
		assertEquals(2, open);

		long closed = FacadeUtil.countReports(pv, ReportStatus.CLOSED);
		assertEquals(3, closed);
	}

	@Test
	public void testCountReportsProjectProjectVersionReportStatus() {
		Project p = new Project();
		p = FacadeUtil.store(p);

		ProjectVersion pv = new ProjectVersion();
		pv.setProject(p);
		pv = FacadeUtil.store(pv);

		Report r = new Report();
		r.setStatus(ReportStatus.OPEN);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setProject(p);
		r.setStatus(ReportStatus.OPEN);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setVersion(pv);
		r.setStatus(ReportStatus.OPEN);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setProject(p);
		r.setVersion(pv);
		r.setStatus(ReportStatus.OPEN);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setStatus(ReportStatus.CLOSED);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setProject(p);
		r.setStatus(ReportStatus.CLOSED);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setVersion(pv);
		r.setStatus(ReportStatus.CLOSED);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setProject(p);
		r.setVersion(pv);
		r.setStatus(ReportStatus.CLOSED);
		r = FacadeUtil.store(r);

		long open = FacadeUtil.countReports(null, null, ReportStatus.OPEN);
		assertEquals(1, open);
		open = FacadeUtil.countReports(p, null, ReportStatus.OPEN);
		assertEquals(1, open);
		open = FacadeUtil.countReports(null, pv, ReportStatus.OPEN);
		assertEquals(1, open);
		open = FacadeUtil.countReports(p, pv, ReportStatus.OPEN);
		assertEquals(1, open);

		long closed = FacadeUtil.countReports(null, null, ReportStatus.CLOSED);
		assertEquals(1, closed);
		closed = FacadeUtil.countReports(p, null, ReportStatus.CLOSED);
		assertEquals(1, closed);
		closed = FacadeUtil.countReports(null, pv, ReportStatus.CLOSED);
		assertEquals(1, closed);
		closed = FacadeUtil.countReports(p, pv, ReportStatus.CLOSED);
		assertEquals(1, closed);
	}

	@Test
	public void testGetAssignedReports() {
		Project p = new Project();
		p = FacadeUtil.store(p);

		ProjectVersion pv = new ProjectVersion();
		pv = FacadeUtil.store(pv);

		Reporter u = new Reporter();
		u = FacadeUtil.store(u);

		Report r = new Report();
		r.setProject(p);
		r.setVersion(pv);
		r.setAssigned(u);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setProject(p);
		r.setVersion(pv);
		r.setAssigned(u);
		r = FacadeUtil.store(r);

		r = new Report();
		r.setProject(p);
		r.setVersion(pv);
		r = FacadeUtil.store(r);

		List<Report> assigned = FacadeUtil.getAssignedReports(p, pv, u);
		assertEquals(2, assigned.size());
	}

	@Test
	public void testSearchReports() {

		Project project = new Project();
		project = FacadeUtil.store(project);

		ProjectVersion version = new ProjectVersion();
		version = FacadeUtil.store(version);

		// Has summary
		Report r = new Report();
		r.setSummary("Report1");
		r.setProject(project);
		r = FacadeUtil.store(r);

		// Has description
		r = new Report();
		r.setVersion(version);
		r.setDescription("Report2");
		r = FacadeUtil.store(r);

		List<Report> result = FacadeUtil.searchReports("Report1", null, null,
				null, null, null, null, true, true, true, true, true, true);
		assertEquals(1, result.size());

		result = FacadeUtil.searchReports("Report2", null, null, null, null,
				null, null, true, true, true, true, true, true);
		assertEquals(1, result.size());

		result = FacadeUtil.searchReports("report", null, null, null, null,
				null, null, true, true, true, true, true, true);
		assertEquals(2, result.size());

		result = FacadeUtil.searchReports(null, project, null, null, null,
				null, null, false, true, true, true, true, true);
		assertEquals(1, result.size());

		result = FacadeUtil.searchReports(null, null, version, null, null,
				null, null, true, false, true, true, true, true);
		assertEquals(1, result.size());

		// TODO Could be expanded with a million more cases
	}
}
